﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using CSharpParser.Structure;
using CustomTypes.Interfaces.Structure;
using CustomTypes.Interfaces;

namespace CustomTypes.Mono
{

    public class TypeContext : ITypeContext
    {


        private string _filename;
        private DateTime lastWrite;
        private AssemblyDefinition assembly;
        private ReaderParameters parameters;


        public TypeContext(string filename)
        {

            _filename = filename;
            lastWrite = DateTime.MinValue;

            parameters = new ReaderParameters()
            {
                ReadingMode = ReadingMode.Immediate,
                AssemblyResolver = new CustomAssemblyResolver(),

            };

        }

        #region assembly

        private AssemblyDefinition GetAssembly()
        {

            if (lastWrite < System.IO.File.GetLastWriteTime(_filename))
                assembly = null;

            return assembly ?? (assembly = CreateAssembly());

        }

        private AssemblyDefinition CreateAssembly()
        {
            lastWrite = System.IO.File.GetLastWriteTime(_filename);
            return AssemblyDefinition.ReadAssembly(_filename, parameters);
        }

        #endregion




        #region Implement ITypeContext

        public string AssemblyName { get { return GetAssembly().FullName; } }

        public ITypeStructure GetType(string @namespace, string name)
        {

            AssemblyDefinition ass = GetAssembly();

            var types = ass.MainModule.GetTypes();

            foreach (TypeReference type in types)
                if (type.Name == name)
                    if (type.Namespace == @namespace)
                        return CreateType(type);

            return null;

        }


        public IEnumerable<ITypeStructure> GetTypes(HashSet<string> namespaces)
        {
            AssemblyDefinition ass = GetAssembly();

            var types = ass.MainModule.GetTypes();

            foreach (TypeReference type in types)
                if (namespaces == null || @namespaces.Contains(type.Namespace))
                    yield return CreateType(type);

        }

        public void Refresh() { assembly = null; }
        public void Clear() { assembly = null; }

        #endregion


        private ITypeStructure CreateType(TypeReference type)
        {
            return new TypeMonoStructure(null, type, type.FullName);
        }

        

    }
}
